Conversation
|
🧪 Testing To try out this version of the SDK: Expires at: Sat, 09 May 2026 10:51:36 GMT |
|
Canary encountered an internal error while analyzing this PR. |
6972295 to
d19a5b9
Compare
Confidence Score: 5/5 - Safe to Merge
|
d19a5b9 to
76a7033
Compare
Confidence Score: 5/5 - Safe to Merge
|
76a7033 to
abd5f3a
Compare
Confidence Score: 5/5 - Safe to Merge
|
abd5f3a to
651d17f
Compare
Confidence Score: 5/5 - Safe to Merge
|
651d17f to
fc292db
Compare
Confidence Score: 5/5 - Safe to Merge
|
fc292db to
08cc52a
Compare
Confidence Score: 5/5 - Safe to Merge
|
Release version edited manuallyThe Pull Request version has been manually set to If you instead want to use the version number |
08cc52a to
15abf4d
Compare
Confidence Score: 5/5 - Safe to Merge
|
15abf4d to
2dbef30
Compare
Confidence Score: 5/5 - Safe to Merge
|
2dbef30 to
b86942f
Compare
Confidence Score: 5/5 - Safe to Merge
|
b86942f to
dd246c5
Compare
Confidence Score: 5/5 - Safe to Merge
|
0b83ccb to
d4e4451
Compare
Confidence Score: 5/5 - Safe to Merge
|
Confidence Score: 5/5 - Safe to Merge
|
d4e4451 to
a7b2b11
Compare
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — Key Findings:
Files requiring special attention
|
f29ed6a to
fce5750
Compare
| import { Hyperspell, ClientOptions } from 'hyperspell'; | ||
|
|
||
| async function tseval(code: string) { |
There was a problem hiding this comment.
Correctness: The code argument passed to tseval originates directly from the request body (req.json()) with no sandboxing beyond the proxy — a malicious caller can execute arbitrary code in the worker process by crafting the code field of the request payload.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts at lines 8-10, the tseval function dynamically imports and executes arbitrary TypeScript code that comes directly from an untrusted HTTP request body. Ensure this worker runs in a fully isolated sandbox (e.g., a separate Deno/Worker process with no access to secrets or the filesystem), enforce strict origin/auth checks before the fetch handler is invoked, or document the trust boundary explicitly if the endpoint is internal-only.
| const log_lines: string[] = []; | ||
| const err_lines: string[] = []; | ||
| const console = { | ||
| const originalConsole = globalThis.console; | ||
| globalThis.console = { | ||
| ...originalConsole, | ||
| log: (...args: unknown[]) => { | ||
| log_lines.push(util.format(...args)); | ||
| }, |
There was a problem hiding this comment.
Correctness: 🐛 Mutating globalThis.console is not safe under concurrent requests — if two requests are in-flight simultaneously, Request B will overwrite globalThis.console with its own capture object, so Request A's console.log calls will be recorded into B's log_lines, and the finally restores will race each other. The previous local const console shadowing was request-scoped; this new approach makes console capture a shared mutable global that breaks under concurrency.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts, lines 271-278, the diff replaces a local `const console = {...}` with a mutation of `globalThis.console`. This creates a race condition when multiple requests are handled concurrently: whichever request last sets `globalThis.console` wins, causing cross-request log capture pollution and lost logs. Fix this by using an AsyncLocalStorage or similar per-request context to pass the capture console to the evaluated code, rather than mutating the shared global. Alternatively, if evaluated code must use globalThis.console, serialize request handling or find another isolation mechanism.
|
|
||
| export interface MemoryUploadParams { | ||
| /** | ||
| * The file to ingest. |
There was a problem hiding this comment.
Correctness: Changing file from Uploadable to string breaks callers passing File, Blob, Buffer, or ReadableStream objects, which are the expected input types for a multipart file upload using multipartFormRequestOptions. A plain string value passed to multipartFormRequestOptions will be sent as-is (e.g. a filename string), not as actual binary file content, silently producing malformed uploads.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In `src/resources/memories.ts`, line 844, the `file` field in `MemoryUploadParams` was changed from `Uploadable` to `string`. This breaks the ability to pass actual file objects (File, Blob, Buffer, ReadableStream) to the upload method, which relies on `multipartFormRequestOptions` for multipart form data. Revert this field back to `Uploadable` to preserve correct upload behavior and maintain API compatibility.
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — this PR introduces critical security and correctness issues that must be resolved before merging. The Key Findings:
Files requiring special attention
|
fce5750 to
7d81670
Compare
| import { Hyperspell, ClientOptions } from 'hyperspell'; | ||
|
|
||
| async function tseval(code: string) { | ||
| return import('data:application/typescript;charset=utf-8;base64,' + Buffer.from(code).toString('base64')); |
There was a problem hiding this comment.
Correctness: Buffer is a Node.js global not available in Deno or edge runtimes; the parseError function explicitly mentions Deno and the module uses export default { fetch } (edge worker pattern), so this will throw ReferenceError: Buffer is not defined at runtime in those environments.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts at line 11, the `tseval` function uses `Buffer.from(code).toString('base64')` to base64-encode the TypeScript code. `Buffer` is a Node.js-only global and is not available in Deno or edge runtimes (the file uses `export default { fetch }` pattern and `parseError` mentions Deno explicitly). Replace `Buffer.from(code).toString('base64')` with a runtime-agnostic base64 encoding such as `btoa(unescape(encodeURIComponent(code)))` to handle Unicode safely across all environments.
|
|
||
| export interface MemoryUploadParams { | ||
| /** | ||
| * The file to ingest. |
There was a problem hiding this comment.
Correctness: Changing file from Uploadable to string is a breaking change — callers passing File, Blob, Buffer, or ReadableStream objects will now get TypeScript type errors. The upload method still calls multipartFormRequestOptions, which is designed for actual binary file uploads, so restricting to string may silently break real file upload use cases at runtime.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In file `src/resources/memories.ts`, line 844, the type of `file` in `MemoryUploadParams` was changed from `Uploadable` to `string`. This is a breaking change for any caller passing `File`, `Blob`, `Buffer`, or `ReadableStream` objects, and may silently break binary file uploads since the `upload` method still uses `multipartFormRequestOptions`. If the intent is to support both file paths (strings) and actual file objects, restore the type to `Uploadable` (or use a union like `Uploadable | string`). If only string file paths are now supported, verify that `multipartFormRequestOptions` handles plain strings correctly and update the method documentation accordingly.
| const log_lines: string[] = []; | ||
| const err_lines: string[] = []; |
There was a problem hiding this comment.
Correctness: 🔴 Mutating globalThis.console is not concurrency-safe in a server handling multiple simultaneous requests — request B will capture request A's patched console as its originalConsole, and log lines from different requests will bleed into each other's log_lines/err_lines arrays until the finally block restores the wrong reference.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts, lines 271-278, the diff replaces a local `const console` shadow with direct mutation of `globalThis.console`. This is unsafe under concurrent requests: each request saves and restores `globalThis.console`, but overlapping requests can interleave such that (1) one request's `log` override overwrites another's, and (2) the 'original' captured by request B is already request A's patched console. Fix by keeping the original approach of passing a custom console-like object directly to user code (e.g., inject it as a parameter or use a module-scoped override only inside `tseval`) instead of mutating the shared global.
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — this PR has multiple critical, unresolved correctness bugs that have been flagged repeatedly across prior reviews without being addressed. In Key Findings:
Files requiring special attention
|
7d81670 to
2b4d27c
Compare
| const log_lines: string[] = []; | ||
| const err_lines: string[] = []; |
There was a problem hiding this comment.
Correctness: 🐛 Mutating globalThis.console is not safe under concurrent requests. If two requests overlap, Request B captures Request A's overriding console as its originalConsole, and when B's finally block restores it, A's capturing function becomes the permanent global console — leaking captured log lines across requests indefinitely.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts, lines 271-272 introduce a race condition: `globalThis.console` is mutated for the duration of an async request, but concurrent requests can interleave their save/restore operations, causing one request's capturing console to leak as the global after another request's `finally` block runs. Fix this by avoiding mutation of the shared global — instead, pass a custom console object directly into the evaluated code's scope (e.g. inject it as a variable alongside `client`), or use a per-invocation wrapper that does not mutate `globalThis`.
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — this PR introduces multiple critical correctness issues that remain unresolved across 18 prior review comments and are confirmed again in the current review. Specifically, the mutation of Key Findings:
Files requiring special attention
|
2b4d27c to
dfc0fe2
Compare
| const log_lines: string[] = []; | ||
| const err_lines: string[] = []; | ||
| const console = { | ||
| const originalConsole = globalThis.console; | ||
| globalThis.console = { | ||
| ...originalConsole, | ||
| log: (...args: unknown[]) => { | ||
| log_lines.push(util.format(...args)); | ||
| }, |
There was a problem hiding this comment.
Correctness: Mutating globalThis.console is not safe under concurrent requests: if two requests interleave across the await tseval(...) / await run_(...) calls, one request's console override will clobber the other's, causing log lines to be captured into the wrong request's arrays or lost entirely after the finally restores.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts around lines 271-278, the code mutates globalThis.console to capture log output from dynamically evaluated user code. Because the fetch handler is async and yields at `await tseval(...)` and `await run_(...)`, concurrent requests can interleave and overwrite each other's globalThis.console override, causing log lines to be routed to the wrong request's log_lines/err_lines arrays or discarded. Consider passing a scoped console object directly into the evaluated code (e.g., injecting it as a global in the data URL or using a per-request wrapper) instead of mutating the shared globalThis.console.
Confidence Score: 2/5 - Changes NeededNot safe to merge — Key Findings:
Files requiring special attention
|
dfc0fe2 to
532797f
Compare
| const log_lines: string[] = []; | ||
| const err_lines: string[] = []; |
There was a problem hiding this comment.
Correctness: 🐛 Mutating globalThis.console inside an async function creates a race condition: if two requests are in-flight concurrently, the second request overwrites the first's patched console, causing the first request's finally block to restore the wrong original and the second's log capture to be silently dropped or mixed.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In `packages/mcp-server/src/code-tool-worker.ts`, lines 271-272 (and the matching `finally` block), `globalThis.console` is overwritten inside an async `fetch` handler. Because multiple requests can be in-flight concurrently (each `await` is a yield point), a second request will overwrite the first's patched console before the first's `finally` restores it, causing mixed log capture and incorrect restoration. Fix this by avoiding mutation of the shared global: instead of patching `globalThis.console`, pass a local console-like object directly into the evaluated code, or serialize requests so only one patch is active at a time.
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — the Key Findings:
Files requiring special attention
|
532797f to
0e9af24
Compare
0e9af24 to
dc0dced
Compare
| const log_lines: string[] = []; | ||
| const err_lines: string[] = []; | ||
| const console = { | ||
| const originalConsole = globalThis.console; | ||
| globalThis.console = { | ||
| ...originalConsole, | ||
| log: (...args: unknown[]) => { | ||
| log_lines.push(util.format(...args)); | ||
| }, |
There was a problem hiding this comment.
Correctness: 🔴 Mutating globalThis.console is shared mutable state — if two requests execute concurrently, one request's finally block will restore the original console while the other request is still running, causing its log/error output to escape capture (or be lost entirely) and potentially mixing log lines across requests.
🤖 AI Agent Prompt for Cursor/Windsurf
📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue
In packages/mcp-server/src/code-tool-worker.ts, lines 271-278, the code mutates `globalThis.console` to intercept log/error calls during user code execution. This creates a race condition in concurrent request handling: if two requests overlap, one request's `finally` block restoring `globalThis.console = originalConsole` will clobber the other request's override mid-execution. Fix this by not mutating `globalThis.console` at all — instead, pass a custom console object directly into the evaluated code's scope, or use a mechanism that doesn't rely on global mutable state. For example, pass the overridden console as a variable that the evaluated code can close over, rather than replacing the global.
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — this PR introduces a critical race condition in Key Findings:
Files requiring special attention
|
Confidence Score: 1/5 - Blocking IssuesNot safe to merge — Key Findings:
Files requiring special attention
|
Automated Release PR
0.35.1 (2026-04-09)
Full Changelog: v0.35.0...v0.35.1
Features
Bug Fixes
oidcdir (a305f3d)Chores
Refactors
This pull request is managed by Stainless's GitHub App.
The semver version number is based on included commit messages. Alternatively, you can manually set the version number in the title of this pull request.
For a better experience, it is recommended to use either rebase-merge or squash-merge when merging this pull request.
🔗 Stainless website
📚 Read the docs
🙋 Reach out for help or questions